package test.abstractFactory;

/**
 * 抽象工厂模式
 * 前两次都是使用计算器的案例，这次我们换一个案例，
 * 假如现在项目中有需要在不同的地方使用不一样的数据库，我们要怎么设计才最合理呢？(mysql,oracle)
 *  优点：
 *  1.便于产品系列的更换
 *  缺点：
 *  1.增加系统的复杂度
 *  2.增加一个表需要增加很多的类，比较麻烦
 * **/
public class AbstractFactory {

    /**
     * 客户端代码
     * **/
    public static void main(String[] args) {

        /**
         * 在这里，我们只需要替换工厂类，就能达到更换数据库的效果，我们还能进一步完善它，通过配置文件，利用反射，在结合spring的ioc，去修改这个工厂类
         * 这里的调用流程，以mysql为例：
         *      MysqlFactory --> getUser() --> MysqlUser
         *
         * 想象一下，如果我们需要新增一个表，需要做什么工作？
         * 1.添加这个表的bean
         * 2.增加一个这个表的父类接口(如：IUser)
         * 3.增加对应数据库的实现类
         * 4.在IFactory中添加对应的get方法
         * 5.在各个数据库的实现类中实现对应的get方法
         *
         * 再想象一下，如果我们增加一个数据库，需要做什么工作？
         * 1.增加一个IFactory的实现类
         * 2.在实现类中实现对应的所有方法
         * 3.增加这个数据库相关表的所有表操作的实现类
         *
         * 是不是感觉挺麻烦的，但是，你得知道，如果真的修改数据库，
         * 如果不作一些设计，直接增加，你要修改的代码可不止这一点，而且极其不灵活。
         * **/
        //创建一个工厂类
        IFactory factory = new OracleFactory();

        //使用工厂类获取User表的操作类
        IUser user = factory.getUser();

        //使用user操作数据库
        System.out.println(user.getUser());


    }

}


/**
 * 工厂抽象类
 * **/
interface IFactory{

     IUser getUser();

}

/**
 * mysql的工厂类
 * **/
class MysqlFactory implements IFactory{

    @Override
    public IUser getUser() {
        return new MysqlUser();
    }
}

/**
 * Oracle工厂
 * **/
class OracleFactory implements IFactory{

    @Override
    public IUser getUser() {
        return new OracleUser();
    }
}



/**
 * User表相关操作的父类
 * **/
interface IUser{

    User getUser();

    boolean insert(User user);

}

/**
 * Mysql数据库的User表的实现类
 * **/
class MysqlUser implements IUser{

    @Override
    public User getUser() {
        return new User("Mysql用户",1);
    }

    @Override
    public boolean insert(User user) {
        return false;
    }
}

/**
 * oracle数据库的User表的实现类
 * **/
class OracleUser implements IUser{

    @Override
    public User getUser() {
        return  new User("Oracle用户",1);
    }

    @Override
    public boolean insert(User user) {
        return false;
    }
}


/**
 * 用户表
 * **/
class User{

    private String username;

    private int age;

    public User(){}

    public User(String username, int age) {
        this.username = username;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", age=" + age +
                '}';
    }
}
